/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using DaveSexton.Controls;
using DaveSexton.DocProject.Sandcastle.TopicManagement;
using System.Xml;

namespace DaveSexton.DocProject.Sandcastle.ContentManagement
{
	public sealed class XmlCommentSectionContentItem : ContentItem
	{
		#region Public Properties
		public string ParameterName
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return parameterName;
			}
		}

		public XmlElement Element
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return element;
			}
		}

		public override string Value
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);
				
				return base.Value;
			}
			set
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				base.Value = value;
			}
		}

		public override ContentItemEditModes EditModes
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return section.EditModes;
			}
		}

		public override ICollection<string> Subsections
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return section.Subsections;
			}
		}

		public override bool Multiple
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return section.AllowMultiplePerTopic;
			}
		}

		public override bool IsVisible
		{
			get
			{
				return !IsDeleted;
			}
		}

		public override ContentItemAttributeDataCollection Attributes
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return attributes;
			}
		}

		public override bool ShowAttributes
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return !section.IsMarkerOnly && (section.IsCustom || (attributes.Count > 0
					&& !string.Equals(section.Name, "param", StringComparison.Ordinal)
					&& !string.Equals(section.Name, "typeparam", StringComparison.Ordinal)));
			}
		}

		public override bool CanEditAttributes
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return section.IsCustom;
			}
		}

		public override bool CanEditAttributeValues
		{
			get
			{
				if (deleteRequired || deleted)
					throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

				return parameterName == null;
			}
		}

		public bool IsDeleted
		{
			get
			{
				return deleteRequired || deleted;
			}
		}
		#endregion

		#region Private / Protected
		internal string RawValue
		{
			set
			{
				element.InnerXml = value;
			}
		}

		private bool deleteRequired, deleted;
		private readonly string parameterName;
		private readonly XmlElement element;
		private readonly ITopicSection section;
		private readonly XmlCommentSectionContentItemAttributeDataCollection attributes;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="XmlCommentSectionContentItem" /> class.
		/// </summary>
		public XmlCommentSectionContentItem(XmlElement element, ITopicSection section, string parameterName)
			: base(section.Name, section.EditModes)
		{
			if (element == null)
				throw new ArgumentNullException("element");

			if (section == null)
				throw new ArgumentNullException("section");

			// NOTE: allow null for parameterName since it only applies to a content item that represents a parameter or type parameter.
			this.parameterName = parameterName;
			this.element = element;
			this.section = section;
			this.attributes = new XmlCommentSectionContentItemAttributeDataCollection(this, base.Name, element);

			foreach (XmlCommentSectionAttributeData attribute in section.Attributes)
				this.attributes.Add(new XmlCommentSectionContentItemAttributeData(
					this, section.Name, attribute.Name, parameterName ?? element.GetAttribute(attribute.Name),
					element, attribute));

			if (base.EditModes != ContentItemEditModes.None && !element.IsEmpty)
				Value = element.InnerXml;

			IsDirty = false;
		}
		#endregion

		#region Methods
		public override string ToString()
		{
			if (deleteRequired || deleted)
				return "{Deleted}";

			if (parameterName != null)
				return Name + " name=\"" + parameterName + "\"";
			else
				return Name;
		}

		public override bool Delete()
		{
			if (deleted)
				return true;

			if ((section.IsCustom || section.AllowMultiplePerTopic || section.IsMarkerOnly) && parameterName == null)
			{
				deleteRequired = true;
				IsDirty = true;

				if (Document != null)
					Document.NotifyItemChanged(this);

				return true;
			}
			else
				return false;
		}

		public void CommitChanges()
		{
			if (deleteRequired)
			{
				element.ParentNode.RemoveChild(element);

				deleteRequired = false;
				deleted = true;
			}
			else if (!deleted)
			{
				foreach (XmlCommentSectionContentItemAttributeData attribute in attributes)
					attribute.CommitChanges();

				element.InnerXml = Value;
			}
		}

		public void CancelChanges()
		{
			if (deleted)
				throw new InvalidOperationException(Resources.Errors.ContentItemDeleted);

			deleteRequired = false;

			foreach (XmlCommentSectionContentItemAttributeData attribute in attributes)
				attribute.CancelChanges();

			if (IsValueEditable)
				Value = element.InnerXml;
			
			// NOTE: Do not set IsDirty to false since previously committed changes may still need to be saved
		}
		#endregion
	}
}
